package com.minimalist.common.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * 通用定时任务服务
 *
 * @author 11987
 */
@Service
public class ScheduleTaskService {
    private static final Logger log = LoggerFactory.getLogger(ScheduleTaskService.class);

    private TaskScheduler taskScheduler;
    private final Map<String, TaskInfo> taskMap = new ConcurrentHashMap<>();

    /**
     * 启动定时任务
     *
     * @param taskId          任务ID
     * @param taskName        任务名称
     * @param count           目标处理数量
     * @param intervalSeconds 间隔秒数
     * @param taskExecutor    任务执行器
     * @return 是否成功启动
     */
    public boolean startTask(String taskId, String taskName, int count, int intervalSeconds,
                             Supplier<Integer> taskExecutor) {
        if (taskMap.containsKey(taskId) && taskMap.get(taskId).isRunning.get()) {
            log.info("任务[{}]已在运行中，无法重复启动", taskName);
            return false;
        }

        if (taskScheduler == null) {
            ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
            // 支持多任务并行
            scheduler.setPoolSize(5);
            scheduler.setThreadNamePrefix("schedule-task-");
            scheduler.initialize();
            taskScheduler = scheduler;
        }

        TaskInfo taskInfo = taskMap.computeIfAbsent(taskId, _ -> new TaskInfo());
        taskInfo.taskName = taskName;
        taskInfo.targetCount.set(count);
        taskInfo.processedCount.set(0);
        taskInfo.isRunning.set(true);

        taskInfo.scheduledTask = taskScheduler.scheduleAtFixedRate(() -> {
            // 使用 TraceIdUtil 包装任务执行
            TraceIdUtil.runWithTraceId(() -> {
                try {
                    if (!taskInfo.isRunning.get()
                            || taskInfo.processedCount.get() >= taskInfo.targetCount.get()) {
                        stopTask(taskId);
                        return;
                    }

                    int result = taskExecutor.get();
                    if (result > 0) {
                        taskInfo.processedCount.addAndGet(result);
                        log.info("任务[{}]执行中，当前进度: {}/{}", taskName,
                                taskInfo.processedCount.get(), taskInfo.targetCount.get());
                    }
                } catch (Exception e) {
                    log.error("任务[{}]执行异常", taskName, e);
                }
            });
        }, intervalSeconds * 1000L);

        log.info("任务[{}]已启动，目标数量: {}, 间隔: {}秒", taskName, count, intervalSeconds);
        return true;
    }

    /**
     * 停止定时任务
     *
     * @param taskId 任务ID
     * @return 是否成功停止
     */
    public boolean stopTask(String taskId) {
        TaskInfo taskInfo = taskMap.get(taskId);
        if (taskInfo == null || !taskInfo.isRunning.get()) {
            log.info("任务[{}]未运行，无需停止", taskId);
            return false;
        }

        if (taskInfo.scheduledTask != null) {
            taskInfo.scheduledTask.cancel(false);
            taskInfo.scheduledTask = null;
        }

        taskInfo.isRunning.set(false);
        log.info("任务[{}]已停止，完成数量: {}/{}", taskInfo.taskName,
                taskInfo.processedCount.get(), taskInfo.targetCount.get());
        return true;
    }

    /**
     * 获取任务状态
     *
     * @param taskId 任务ID
     * @return 任务状态信息
     */
    public TaskStatus getTaskStatus(String taskId) {
        TaskInfo taskInfo = taskMap.get(taskId);
        if (taskInfo == null) {
            return new TaskStatus(null, 0, 0, false);
        }

        int progressPercent = taskInfo.processedCount.get() >= taskInfo.targetCount.get() ? 100
                : taskInfo.targetCount.get() > 0
                ? (int) ((double) taskInfo.processedCount.get() / taskInfo.targetCount.get() * 100)
                : 0;

        return new TaskStatus(
                taskInfo.taskName,
                taskInfo.targetCount.get(),
                taskInfo.processedCount.get(),
                taskInfo.isRunning.get());
    }

    /**
     * 获取所有任务状态
     *
     * @return 所有任务状态信息
     */
    public Map<String, TaskStatus> getAllTaskStatus() {
        Map<String, TaskStatus> result = new ConcurrentHashMap<>();
        taskMap.forEach((id, info) -> {
            result.put(id, new TaskStatus(
                    info.taskName,
                    info.targetCount.get(),
                    info.processedCount.get(),
                    info.isRunning.get()));
        });
        return result;
    }

    /**
     * 任务信息
     */
    private static class TaskInfo {
        String taskName;
        AtomicInteger targetCount = new AtomicInteger(0);
        AtomicInteger processedCount = new AtomicInteger(0);
        AtomicBoolean isRunning = new AtomicBoolean(false);
        ScheduledFuture<?> scheduledTask;
    }

    /**
     * 任务状态
     */
    public static class TaskStatus {
        private String taskName;
        private int targetCount;
        private int processedCount;
        private boolean isRunning;

        public TaskStatus() {
        }

        public TaskStatus(String taskName, int targetCount, int processedCount, boolean isRunning) {
            this.taskName = taskName;
            this.targetCount = targetCount;
            this.processedCount = processedCount;
            this.isRunning = isRunning;
        }

        public String getTaskName() {
            return taskName;
        }

        public void setTaskName(String taskName) {
            this.taskName = taskName;
        }

        public int getTargetCount() {
            return targetCount;
        }

        public void setTargetCount(int targetCount) {
            this.targetCount = targetCount;
        }

        public int getProcessedCount() {
            return processedCount;
        }

        public void setProcessedCount(int processedCount) {
            this.processedCount = processedCount;
        }

        public boolean isRunning() {
            return isRunning;
        }

        public void setRunning(boolean running) {
            isRunning = running;
        }
    }
}
